package frsf.cidisi.exercise.tp1.search;

import frsf.cidisi.faia.simulator.Log;
import frsf.cidisi.exercise.tp1.interfaz.ControlSimulacion;
import frsf.cidisi.exercise.tp1.interfaz.Principal;
import frsf.cidisi.exercise.tp1.search.actions.AvanzarAAragaey;
import frsf.cidisi.exercise.tp1.search.actions.AvanzarAAse;
import frsf.cidisi.exercise.tp1.search.actions.AvanzarABresol;
import frsf.cidisi.exercise.tp1.search.actions.AvanzarABulovoe;
import frsf.cidisi.exercise.tp1.search.actions.AvanzarACabe;
import frsf.cidisi.exercise.tp1.search.actions.AvanzarACenede;
import frsf.cidisi.exercise.tp1.search.actions.AvanzarAErgintone;
import frsf.cidisi.exercise.tp1.search.actions.AvanzarAIcaedur;
import frsf.cidisi.exercise.tp1.search.actions.AvanzarAMixocu;
import frsf.cidisi.exercise.tp1.search.actions.AvanzarAPeregay;
import frsf.cidisi.exercise.tp1.search.actions.AvanzarAVinizaile;
import frsf.cidisi.exercise.tp1.search.actions.TomarTesoro;
import frsf.cidisi.exercise.tp1.utiles.DatosAmbiente;
import frsf.cidisi.exercise.tp1.utiles.MetodosUtiles;
import frsf.cidisi.exercise.tp1.utiles.Parametros;
import frsf.cidisi.faia.agent.Perception;
import frsf.cidisi.faia.agent.search.Problem;
import frsf.cidisi.faia.agent.search.SearchAction;
import frsf.cidisi.faia.agent.search.SearchBasedAgent;
import frsf.cidisi.faia.agent.Action;
import frsf.cidisi.faia.solver.search.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Vector;

import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

import com.sun.org.apache.xalan.internal.xsltc.runtime.Operators;

public class Arqueologo extends SearchBasedAgent {

	private Parametros parametros;
	private MetodosUtiles metodosUtiles;
	private DatosAmbiente datosAmbiente;
	private Log log;
	private ControlSimulacion controlSimulacion;
		
    public Arqueologo() {

        // The Agent Goal
        ObjetivoArqueologo agGoal = new ObjetivoArqueologo();

        // The Agent State
        EstadoActualArqueologo agState = new EstadoActualArqueologo();
        this.setAgentState(agState);

        // Create the operators
        Vector<SearchAction> operators = new Vector<SearchAction>();
        
        //TODO: Cambio... Cambie el orden de los operadores
        operators.addElement(new TomarTesoro());
        operators.addElement(new AvanzarAAragaey());
        operators.addElement(new AvanzarAAse());
        operators.addElement(new AvanzarABresol());
        operators.addElement(new AvanzarABulovoe());
        operators.addElement(new AvanzarACabe());
        operators.addElement(new AvanzarACenede());
        operators.addElement(new AvanzarAErgintone());
        operators.addElement(new AvanzarAIcaedur());
        operators.addElement(new AvanzarAMixocu());
        operators.addElement(new AvanzarAPeregay());
        operators.addElement(new AvanzarAVinizaile());
      
        // Create the Problem which the agent will resolve
        Problem problem = new Problem(agGoal, agState, operators);
        this.setProblem(problem);
        
    }

    // Numero de escenario pasado por parametro.
    public void actualizarDatosAmbiente(int escenario){
    	
    	((EstadoActualArqueologo)this.getAgentState()).setMapa(this.getDatosAmbiente().getEscenarios().get(escenario-1).getMapa());
    	((EstadoActualArqueologo)this.getAgentState()).setPosicionEnMapa(this.getDatosAmbiente().getEscenarios().get(escenario-1).getPosicionEnMapa());
    	
    	
    	
    }
    
    public void actualizarFuncionObjetivo(){
    	
    	
    	ObjetivoArqueologo auxObjetivo = ((ObjetivoArqueologo)(this.getProblem().getGoalState()));
    	
    	auxObjetivo.setMetodosUtiles(this.getMetodosUtiles());
    	auxObjetivo.setPesoMaximoAcoplado(this.getParametros().getPesoMaximoAcoplado());
    	auxObjetivo.setPesoPorUnidadAnillo(this.getParametros().getPesoPorUnidadAnillo());
    	auxObjetivo.setPesoPorUnidadRubi(this.getParametros().getPesoPorUnidadRubi());
    	auxObjetivo.setPesoPorUnidadDiamante(this.getParametros().getPesoPorUnidadDiamante());
    	auxObjetivo.setPesoPorUnidadColgante(this.getParametros().getPesoPorUnidadColgante());
    	auxObjetivo.setPesoPorUnidadOro(this.getParametros().getPesoPorUnidadOro());
    	
    	auxObjetivo.setPosicionDeseada(this.getParametros().getPosicionDeseada());
    	auxObjetivo.setPorcentajeMinimoDeCarga(this.getParametros().getPorcentajeMinimoDeCarga());
    		
    	
    };
    
    
    public void actualizarMetodosUtiles(){
    	
    		this.getMetodosUtiles().setPesoPorUnidadAnillo(this.getParametros().getPesoPorUnidadAnillo());
    		this.getMetodosUtiles().setPesoPorUnidadRubi(this.getParametros().getPesoPorUnidadRubi());
    		this.getMetodosUtiles().setPesoPorUnidadOro(this.getParametros().getPesoPorUnidadOro());
    		this.getMetodosUtiles().setPesoPorUnidadDiamante(this.getParametros().getPesoPorUnidadDiamante());
    		this.getMetodosUtiles().setPesoPorUnidadColgante(this.getParametros().getPesoPorUnidadColgante());
    		
    		((TomarTesoro)(this.getProblem().getActions().get(0))).setMetodosUtiles(this.getMetodosUtiles());
    }
    
    
    public void actualizarParametros(){
    	
    	String nombreAcciones[] = parametros.getNombreAcciones();
    	Vector<SearchAction> actions = this.getProblem().getActions();
    	 
    	for(int i=0; i<this.getProblem().getActions().size();i++){
    		
    		if(actions.get(i).toString().equals(nombreAcciones[0])){
    			
    			((TomarTesoro)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((TomarTesoro)(actions.get(i))).setCantidadDeTesoros(parametros.getCantidadDeTesoros());
    			((TomarTesoro)(actions.get(i))).setPesoMaximoAcoplado(parametros.getPesoMaximoAcoplado());
    			((TomarTesoro)(actions.get(i))).setPesoPorUnidadAnillo(parametros.getPesoPorUnidadAnillo());
    			((TomarTesoro)(actions.get(i))).setPesoPorUnidadColgante(parametros.getPesoPorUnidadColgante());
    			((TomarTesoro)(actions.get(i))).setPesoPorUnidadDeOro(parametros.getPesoPorUnidadOro());
    			((TomarTesoro)(actions.get(i))).setPesoPorUnidadDiamante(parametros.getPesoPorUnidadDiamante());
    			((TomarTesoro)(actions.get(i))).setPesoPorUnidadRubi(parametros.getPesoPorUnidadRubi());
    			((TomarTesoro)(actions.get(i))).getLog().setLog(log);
    	
    		}
    		else if(actions.get(i).toString().equals(nombreAcciones[1])){
    			
    			((AvanzarAAragaey)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((AvanzarAAragaey)(actions.get(i))).setNombreAldeas(parametros.getNombreAldeas());
    			((AvanzarAAragaey)(actions.get(i))).getLog().setLog(log);
    			
    		}
    		else if(actions.get(i).toString().equals(nombreAcciones[2])){
    			
    			((AvanzarAAse)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((AvanzarAAse)(actions.get(i))).setNombreAldeas(parametros.getNombreAldeas());
    			((AvanzarAAse)(actions.get(i))).getLog().setLog(log);
    		}
    		else if(actions.get(i).toString().equals(nombreAcciones[3])){
    			
    			((AvanzarABresol)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((AvanzarABresol)(actions.get(i))).setNombreAldeas(parametros.getNombreAldeas());
    			((AvanzarABresol)(actions.get(i))).getLog().setLog(log);
    			
    		}
    		else if(actions.get(i).toString().equals(nombreAcciones[4])){
    			
    			((AvanzarABulovoe)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((AvanzarABulovoe)(actions.get(i))).setNombreAldeas(parametros.getNombreAldeas());
    			((AvanzarABulovoe)(actions.get(i))).getLog().setLog(log);
    		}
    		else if(actions.get(i).toString().equals(nombreAcciones[5])){
    			
    			((AvanzarACabe)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((AvanzarACabe)(actions.get(i))).setNombreAldeas(parametros.getNombreAldeas());
    			((AvanzarACabe)(actions.get(i))).getLog().setLog(log);
    			
    		}
    		else if(actions.get(i).toString().equals(nombreAcciones[6])){
    			
    			((AvanzarACenede)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((AvanzarACenede)(actions.get(i))).setNombreAldeas(parametros.getNombreAldeas());
    			((AvanzarACenede)(actions.get(i))).getLog().setLog(log);
    			
    		}
    		else if(actions.get(i).toString().equals(nombreAcciones[7])){
    			
    			((AvanzarAErgintone)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((AvanzarAErgintone)(actions.get(i))).setNombreAldeas(parametros.getNombreAldeas());
    			((AvanzarAErgintone)(actions.get(i))).getLog().setLog(log);
    			
    		}
    		else if(actions.get(i).toString().equals(nombreAcciones[8])){
    			
    			((AvanzarAIcaedur)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((AvanzarAIcaedur)(actions.get(i))).setNombreAldeas(parametros.getNombreAldeas());
    			((AvanzarAIcaedur)(actions.get(i))).getLog().setLog(log);
    		}
    		else if(actions.get(i).toString().equals(nombreAcciones[9])){
    			
    			((AvanzarAMixocu)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((AvanzarAMixocu)(actions.get(i))).setNombreAldeas(parametros.getNombreAldeas());
    			((AvanzarAMixocu)(actions.get(i))).getLog().setLog(log);
    			
    		}
    		else if(actions.get(i).toString().equals(nombreAcciones[10])){
    			
    			((AvanzarAPeregay)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((AvanzarAPeregay)(actions.get(i))).setNombreAldeas(parametros.getNombreAldeas());
    			((AvanzarAPeregay)(actions.get(i))).getLog().setLog(log);
    			
    		}
    		else if(actions.get(i).toString().equals(nombreAcciones[11])){
    			
    			((AvanzarAVinizaile)(actions.get(i))).setCantidadAldeas(parametros.getCantidadAldeas());
    			((AvanzarAVinizaile)(actions.get(i))).setNombreAldeas(parametros.getNombreAldeas());
    			((AvanzarAVinizaile)(actions.get(i))).getLog().setLog(log);
    			
    		}
    		  		
    		
    	}
    	
    	
    	
    	
    	
    	
    }
    
    public void actualizarHeuristic(Heuristic heuristic){
    	
    	heuristic.setMetodosUtiles(this.getMetodosUtiles());
    	heuristic.setPesoMaximoAcoplado(this.getParametros().getPesoMaximoAcoplado());
    	heuristic.setPonderacionPesoTesoro(this.getParametros().getPonderacionPesoTesoro());
    	heuristic.setPesoPorUnidadAnillo(this.getParametros().getPesoPorUnidadAnillo());
    	heuristic.setPesoPorUnidadRubi(this.getParametros().getPesoPorUnidadRubi());
    	heuristic.setPesoPorUnidadDiamante(this.getParametros().getPesoPorUnidadDiamante());
    	heuristic.setPesoPorUnidadColgante(this.getParametros().getPesoPorUnidadColgante());
    	heuristic.setPesoPorUnidadOro(this.getParametros().getPesoPorUnidadOro());
    	
    }
    
    public void actualizarCostFunction(CostFunction costFunction){
    	
    	costFunction.setPonderacionDistancia(parametros.getPonderacionDistancia());
    }

    /**
     * This method is executed by the simulator to ask the agent for an action.
     */
    @Override
    public Action selectAction() {
 
    	new SwingWorker<Object, Object>(){

			@Override
			protected Object doInBackground() throws Exception {
			
				getControlSimulacion().actualizarEstadoEnInterfaz();
			
				return null;
			}
		
		}.execute();
      	

     
        Strategy strategy = null;
    	    	 
    	String estrategia = parametros.getEstrategia();
    	
    	if(estrategia.equals("Profundidad")){
    		
    		strategy = new DepthFirstSearch();
    		
    	}
    	else if(estrategia.equals("CostoUniforme")){
    		CostFunction funcionCosto = new CostFunction();
				actualizarCostFunction(funcionCosto);
    		 strategy = new UniformCostSearch(funcionCosto);
    	}
    	else if(estrategia.equals("Anchura")){
    		
    		strategy = new BreathFirstSearch();
    	}
    	else if(estrategia.equals("Avara")){
    		
    		Heuristic heuristic = new Heuristic();
        	actualizarHeuristic(heuristic);
            strategy = new GreedySearch(heuristic);
    		
    	}
    	else if(estrategia.equals("Estrella")){
    			
    		CostFunction funcionCosto = new CostFunction();
    			actualizarCostFunction(funcionCosto);
    		Heuristic heuristic = new Heuristic();
        		actualizarHeuristic(heuristic);

        	strategy = new AStarSearch(funcionCosto,heuristic);
    	}
    	    	
    	// Create a Search object with the strategy
        Search searchSolver = new Search(strategy);

        /* Generate an XML file with the search tree. It can also be generated
         * in other formats like PDF with PDF_TREE */
        searchSolver.setVisibleTree(Search.EFAIA_TREE);
        
        // Set the Search searchSolver.
        this.setSolver(searchSolver);

        (this.getSolver()).setLog(getLog());
       
        
        // Ask the solver for the best action
        Action selectedAction = null;
        
        try {
            selectedAction = this.getSolver().solve(new Object[]{this.getProblem()});
           
       
            if(getParametros().isGenerarArbol()){
            	searchSolver.showTree();
            }

        } catch (Exception ex) {
            Logger.getLogger(Arqueologo.class.getName()).log(Level.SEVERE, null, ex);
        }

    	//TODO: PROBANDO
//        getControlSimulacion().actualizarEstadoEnInterfaz();
        
//        System.out.println(selectedAction.toString());
//        
//        Asi esta implementado en el ejemplo del snake
//        
//        if (accionSeleccionada.toString().equals("Avanzar")) {
//            this.calculador.reportarAccion(Calculador.AVANZAR);
//        } else if (accionSeleccionada.toString().equals("Comer")) {
//            this.calculador.reportarAccion(Calculador.COMER);
//        } else {
//            this.calculador.reportarAccion(Calculador.GIRAR);        // Retorna la acción seleccionada.-
//        }
    
        
        // Return the selected action
        return selectedAction;

    }

    /**
     * This method is executed by the simulator to give the agent a perception.
     * Then it updates its state.
     * @param p
     */
    @Override
    public void see(Perception p) {
    
        this.getAgentState().updateState(p);
    }

	public void setParametros(Parametros parametros) {
		this.parametros = parametros;
	}

	public Parametros getParametros() {
		return parametros;
	}

	public void setMetodosUtiles(MetodosUtiles metodosUtiles) {
		this.metodosUtiles = metodosUtiles;
	}

	public MetodosUtiles getMetodosUtiles() {
		return metodosUtiles;
	}

	public void setDatosAmbiente(DatosAmbiente datosAmbiente) {
		this.datosAmbiente = datosAmbiente;
	}

	public DatosAmbiente getDatosAmbiente() {
		return datosAmbiente;
	}

	public void setLog(Log log) {
		this.log = log;
	}

	public Log getLog() {
		return log;
	}

	public void setControlSimulacion(ControlSimulacion controlSimulacion) {
		this.controlSimulacion = controlSimulacion;
	}

	public ControlSimulacion getControlSimulacion() {
		return controlSimulacion;
	}

}

